﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

// Ooganizer Namespaces
using Ooganizer.Platform;
using Ooganizer.Platform.Win32;
using System.Diagnostics;

namespace Ooganizer.Client.UI
{
    /// <summary>
    /// This is the generic GUICommon Class, that serves us a generic implementation to
    /// everyone as to isolate ourselves from OS Changes
    /// </summary>
    public class GUICommon
    {
        // Keep track of all the origianl window positions that go
        // thru here, ~we delete them when position back to org position
        // get's called.
        private static Dictionary<IntPtr,RECT> s_orgWindowPosMap;

        // keep track of Window Positions
        static GUICommon()
        {
            s_orgWindowPosMap = new Dictionary<IntPtr, RECT>();
        }

        /// <summary>
        /// Performs a screen snapshot of the passed in window handle.
        /// </summary>
        /// <param name="hWnd">Window to Snap</param>
        /// <returns>a window image</returns>
        public Image PerformSnapshot(IntPtr hWnd)
        {        
            if (hWnd != IntPtr.Zero)
            {
                ScreenCapture screencap = new ScreenCapture();

                if (Env.Theme == Env.Themes.AeroTheme)
                    return screencap.SaveWindowUsingFullScreenShotCrop(hWnd);
                else
                    return screencap.SaveWindowUsingDCNBitBlt(hWnd, false);
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hWnd"></param>
        public Image PositionWindowToGoldenPosAndTakeSnapshot(IntPtr hWnd)
        {
            // First thing to do is to save the org position
            RECT rect;
            Win32Functions.GetWindowRect(hWnd, out rect);
            s_orgWindowPosMap[hWnd] = rect;

            // First we fade the window totally away
            FadeWindowIntoItself(hWnd);

            // now we want to fade it out of the monitor center
            // However using the golden ratio as the size
            FadeWindowOutOfMonitorCenterInGoldenRatio(hWnd, rect);

            // Make sure we are in position and drawing at this point,
            // perform the snapshot and return
            System.Threading.Thread.Sleep(10);
            return PerformSnapshot(hWnd);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hWnd"></param>
        public void PositionWindowBackToWhereItWas(IntPtr hWnd)
        {
            // try to retrieve the org value from the map
            if (!s_orgWindowPosMap.ContainsKey(hWnd))
                return;

            RECT orgRect = s_orgWindowPosMap[hWnd];

            // First we fade the window totally away ... again
            FadeWindowIntoItself(hWnd);

            // Now just flat out position it back to where it was
            Win32_WrapperFunc.SetAlphaChannel(hWnd, 0); // invisible
            Win32Functions.SetWindowPos(hWnd, IntPtr.Zero, orgRect.left, orgRect.top, orgRect.AsRectangle.Width, orgRect.AsRectangle.Height, (uint) SetWindowPosFlags.SWP_SHOWWINDOW);
            Win32_WrapperFunc.SetAlphaChannel(hWnd, 255); // visible

            // since we positioned the window back to where it was,
            // we no longer need to keep track of it's org position
            s_orgWindowPosMap.Remove(hWnd);
        }

        /// <summary>
        /// The Golden Ratio (~1.618) is used for the Snapshot to give it the best look
        /// </summary>
        /// <param name="screen">pass in th screen for which to calculate the ratio for</param>
        /// <param name="rect">the width and height to achieve the best golden ratio for that screen</param>
        private void CalculateGoldenRatio(Screen screen, out RECT rect)
        {
            const double _fGoldenRatio = 1.618;
            const double _fsafetybuffer = .2; // 20% just in case 
                                              // safety buffer for height/width

            int maxHeight = screen.WorkingArea.Height;
            int maxWidth = screen.WorkingArea.Width;

            // calculated height and width;
            int height = maxHeight - (int)(((double) maxHeight / 100) * _fsafetybuffer);
            int width = (int) ((double) height / _fGoldenRatio);

            bool bIsPortrait = maxHeight > maxWidth;
            if (bIsPortrait)
            {
                const int _widthHeightsafetypixels = 30;
                if (width > (maxWidth - _widthHeightsafetypixels)) // we need to redo our calculations using width as the guide
                {                            // use 30 pixels as a buffer, we never want it to take up 
                                             // the whole width
                    width = maxWidth - (int) (((double) maxWidth / 100) * _fsafetybuffer);
                    height = (int) ((double) width * _fGoldenRatio);
                    Debug.Assert(height < maxHeight);
                } 
            }

            // pass out the calculated height and width
            rect.left = 0;
            rect.top = 0;
            rect.bottom = height;
            rect.right = width;
        }

        /// <summary>
        /// Helper Function responsible for Fading the window into itself.
        /// Fancy, schmancy Fade in effect
        /// </summary>
        private void FadeWindowIntoItself(IntPtr hWnd)
        {
            RECT rect;
            Win32Functions.GetWindowRect(hWnd, out rect);

            // get the inital position
            int y = rect.top;
            int x = rect.left;
            int cy = rect.AsRectangle.Height;
            int cx = rect.AsRectangle.Width;
            
            ////
            // Our goal is to fade the window (resize smaller and
            // fade into itself). ~make smaller and fade in
            ////
            Win32_WrapperFunc.SetAlphaChannel(hWnd, 205);
            Win32Functions.SetWindowPos(hWnd, IntPtr.Zero, (x + 5), (y + 5), (cx - 10), (cy - 10), (uint) SetWindowPosFlags.SWP_SHOWWINDOW);
            System.Threading.Thread.Sleep(10);

            Win32_WrapperFunc.SetAlphaChannel(hWnd, 155);
            Win32Functions.SetWindowPos(hWnd, IntPtr.Zero, (x + 5), (y + 5), (cx - 10), (cy - 10), (uint) SetWindowPosFlags.SWP_SHOWWINDOW);
            System.Threading.Thread.Sleep(10);

            Win32_WrapperFunc.SetAlphaChannel(hWnd, 105);
            Win32Functions.SetWindowPos(hWnd, IntPtr.Zero, (x + 5), (y + 5), (cx - 10), (cy - 10), (uint) SetWindowPosFlags.SWP_SHOWWINDOW);
            System.Threading.Thread.Sleep(10);

            Win32_WrapperFunc.SetAlphaChannel(hWnd, 55);
            Win32Functions.SetWindowPos(hWnd, IntPtr.Zero, (x + 5), (y + 5), (cx - 10), (cy - 10), (uint) SetWindowPosFlags.SWP_SHOWWINDOW);
            System.Threading.Thread.Sleep(10);

            // Set totally transparent - we are done here.
            Win32_WrapperFunc.SetAlphaChannel(hWnd, 0);
        }

        /// <summary>
        /// Helper function to determine the monitor and it's center and
        /// fade out the window there in GoldenRatio Siz
        /// </summary>
        private void FadeWindowOutOfMonitorCenterInGoldenRatio(IntPtr hWnd, RECT orgRect)
        {
            // get the screen the original rect was mostly located
            Screen screen = Screen.FromRectangle(orgRect.AsRectangle);

            // now figure out the best rect to use for this screen 
            RECT goldenRect;
            CalculateGoldenRatio(screen, out goldenRect);

            // figure out the exact center point of the screen
            Point pt = new Point();
            pt.Y = (screen.Bounds.Height / 2);
            pt.X = (screen.Bounds.Width / 2);

            // calculate where we must place the golden window
            pt.Y = pt.Y - (goldenRect.AsRectangle.Width / 2);
            pt.X = pt.X - (goldenRect.AsRectangle.Height / 2);

            // Make the window totally transparent and show it in the golden ratio position
            Win32_WrapperFunc.SetAlphaChannel(hWnd, 0);
            Win32Functions.SetWindowPos(hWnd, IntPtr.Zero, pt.X, pt.Y, goldenRect.AsRectangle.Width, goldenRect.AsRectangle.Height, (uint) SetWindowPosFlags.SWP_SHOWWINDOW);

            ////
            // Our goal is to fade the window out of the center 
            // ~just fade out, since the pos is already correct
            ////
            Win32_WrapperFunc.SetAlphaChannel(hWnd, 55);
            System.Threading.Thread.Sleep(10);

            Win32_WrapperFunc.SetAlphaChannel(hWnd, 105);            
            System.Threading.Thread.Sleep(10);

            Win32_WrapperFunc.SetAlphaChannel(hWnd, 155);
            System.Threading.Thread.Sleep(10);

            Win32_WrapperFunc.SetAlphaChannel(hWnd, 205);
            System.Threading.Thread.Sleep(10);

            // Set totally visible - we are done here.
            Win32_WrapperFunc.SetAlphaChannel(hWnd, 255);
        }

    }
}

